//
//  generateFile.swift
//  xtools
//  代码生成类
//  Created by symbol on 2018/6/1.
//  Copyright © 2018年 symbol. All rights reserved.
//

import Foundation

class generateFile {

    //生成项目主入口
    func crate(obj: baseElement) -> Bool {
        //验证文件夹操作
        let fileManager = FileManager.default
        //项目根路径
        let mainPath: String = "\(NSHomeDirectory() + obj.filepath!)/\(obj.projectName!)/"

        //创建配置文件夹
        let resPath: String = "\(mainPath)res"
        if !fileManager.fileExists(atPath: resPath) {
            //不存在文件夹继续操作
            try! fileManager.createDirectory(atPath: resPath, withIntermediateDirectories: true, attributes: nil)
        }

        //创建页面,lib存储位置
        let webPath: String = "\(mainPath)WebRoot/WEB-INF/lib"
        if !fileManager.fileExists(atPath: webPath) {
            //不存在文件夹继续操作
            //withIntermediateDirectories为ture表示路径中间如果有不存在的文件夹都会创建
            try! fileManager.createDirectory(atPath: webPath, withIntermediateDirectories: true, attributes: nil)
        }

        //创建文件夹存储Java代码位置
        let son = "\(obj.package?.replacingOccurrences(of: ".", with: "/") ?? "")"
        //文件夹路径[直接定位到main文件目录]
        let filePath: String = "\(mainPath)src/\(son)/common"
        let actionPath: String = "\(mainPath)src/\(son)"
        let exist = fileManager.fileExists(atPath: filePath)
        if !exist {
            //不存在文件夹继续操作
            //withIntermediateDirectories为ture表示路径中间如果有不存在的文件夹都会创建
            try! fileManager.createDirectory(atPath: filePath, withIntermediateDirectories: true, attributes: nil)
        }

        /**
         * 获取jar包部分
         */
        //获取jfinal jar包[自动获取最新的jar]
        let jfinalUrl = getHTMLCode(strurl: "https://blog.easymbol.com/jar/jfinal")
        getFile(strurl: jfinalUrl!, path: "\(webPath)/", fileName: "jfinal.jar")
        //获取druid jar包[自动最新的jar]
        let druidurl = getHTMLCode(strurl: "https://blog.easymbol.com/jar/druid.html")
        getFile(strurl: druidurl!, path: "\(webPath)/", fileName: "druid.jar")
        //获取freemarker jar包[自动获取最新的jar]
        let freemarkerurl = getHTMLCode(strurl: "https://blog.easymbol.com/jar/freemarker")
        getFile(strurl: freemarkerurl!, path: "\(webPath)/", fileName: "freemarker.jar")
        //获取log4j jar包[自动最新的jar]
        let log4jurl = getHTMLCode(strurl: "https://blog.easymbol.com/jar/log4j.html")
        getFile(strurl: log4jurl!, path: "\(webPath)/", fileName: "log4j.jar")
        //获取MySQL jar包[自动最新的jar]
        let mysqlurl = getHTMLCode(strurl: "https://blog.easymbol.com/jar/mysql.html")
        getFile(strurl: mysqlurl!, path: "\(webPath)/", fileName: "mysql.jar")
        //获取cos jar包
        getFile(strurl: "https://blog.easymbol.com/jar/jarfile/cos.jar", path: "\(webPath)/", fileName: "cos.jar")
        //获取jetty jar包
        getFile(strurl: "https://blog.easymbol.com/jar/jarfile/jetty-server-8.1.8.jar", path: "\(webPath)/", fileName: "jetty.jar")

        /**
         *  创建文件 部分
         */
        //创建入口class
        let mainfile = "\(filePath)/\(obj.mainclass!).java"
        //预读取的文件
        var codeMain: String = loadFile(filename: "config", filetype: "java")!
        //修正package引用
        codeMain = codeMain.replacingOccurrences(of: "com.qt.common.config", with: "\(obj.package ?? "").common")
        //修正端口号
        codeMain = codeMain.replacingOccurrences(of: "80", with: "\(obj.prot ?? "80")")
        //修正入口名字
        codeMain = codeMain.replacingOccurrences(of: "MainConfig", with: "\(obj.mainclass ?? "")Config")
        //修正数据库连接池的方法
        if obj.dbPool == 2 {
            codeMain = codeMain.replacingOccurrences(of: "C3p0Plugin", with: "DruidPlugin")
        }
        //写文件
        writeFile(filePath: mainfile, content: codeMain)

        //web.xml文件
        let webxmlFile = "\(mainPath)/WebRoot/WEB-INF/web.xml"
        var webxmlContent: String = loadFile(filename: "web", filetype: "xml")!
        //修正数据内容
        webxmlContent = webxmlContent.replacingOccurrences(of: "<filter-name>symbol</filter-name>", with: "<filter-name>\(obj.projectName!)</filter-name>")
        var temp = "\(son)/\(obj.mainclass!)"
        temp = temp.replacingOccurrences(of: "/", with: ".")
        webxmlContent = webxmlContent.replacingOccurrences(of: "com.easymbol.common.MainConfig", with: temp)
        writeFile(filePath: webxmlFile, content: webxmlContent)

        //配置文件
        //log4j
        let log4jFile = "\(mainPath)/res/log4j.properties"
        var log4jContent: String = loadFile(filename: "log4j", filetype: "properties")!
        log4jContent = log4jContent.replacingOccurrences(of: "ceshi", with: obj.projectName!)
        writeFile(filePath: log4jFile, content: log4jContent)

        //config
        let configFile = "\(mainPath)/res/config.properties"
        var configContent: String = loadFile(filename: "config", filetype: "properties")!
        //暂时只匹配mysql
        configContent = configContent.replacingOccurrences(of: "127.0.0.1", with: obj.dbsql!)
        configContent = configContent.replacingOccurrences(of: "3306", with: obj.dbPort!)
        configContent = configContent.replacingOccurrences(of: "symbol", with: obj.dbname!)
        configContent = configContent.replacingOccurrences(of: "root", with: obj.user!)
        configContent = configContent.replacingOccurrences(of: "ce", with: obj.password!)
        let isdev: String = obj.devMode == 1 ? "true" : "false"
        if isdev == "false" {
            configContent = configContent.replacingOccurrences(of: "devMode = true", with: "devMode = false")
        }
        writeFile(filePath: configFile, content: configContent)
        //bean类

        //DAO层
        writeJavaDAOFile(projectPath: actionPath, packagePath: obj.package!)
        return true
    }

    /**
     * 向本地磁盘写入java项目的bean类【基于我的习惯一般路径在project/src/com/自定义/dao/action下面】
     * @param projectPath 文件夹路径【定位于main】
     * @param packagePath 引用路径
     */
    func writeJavaDAOFile(projectPath: String, packagePath: String) {
        //验证文件夹操作
        let fileManager = FileManager.default
        //基类生成路径
        let basePath = "\(projectPath)/dao/action"
        let exist = fileManager.fileExists(atPath: basePath)
        if !exist {
            //不存在文件夹继续操作
            try! fileManager.createDirectory(atPath: basePath, withIntermediateDirectories: true, attributes: nil)
        }
        var str = loadFile(filename: "actiondao", filetype: "java")
        if str == nil {
            str = ""
        }
        str = str!.replacingOccurrences(of: "package com.qt.dao.action;", with: "package \(packagePath).dao.action;")
        writeFile(filePath: "\(basePath)/ActionDao.java", content: str!)
    }

    /**
     * 向本地磁盘写入java项目的bean类【一般路径在project/src/com/自定义/common/baseModel/base下面】
     * @param className 类名
     * @param jz    数据库键值对
     * @param projectPath 文件夹路径[直接定位到main文件目录]
     * @param packageName 包名
     */
    func writeJavaBeanFile(className: String, jz: Dictionary<String, NSObject>, projectPath: String, packageName: String) {
        //验证文件夹操作
        let fileManager = FileManager.default
        //基类生成路径
        let basePath = "\(projectPath)/baseModel/base"
        let exist = fileManager.fileExists(atPath: basePath)
        if !exist {
            //不存在文件夹继续操作
            //withIntermediateDirectories为ture表示路径中间如果有不存在的文件夹都会创建
            try! fileManager.createDirectory(atPath: basePath, withIntermediateDirectories: true, attributes: nil)
        }
        let baseJavaPath = "\(basePath)/\(className).java"
        let beanCode: String = javaBeanCode(package: "\(packageName).common.baseModel.base", jz: jz, className: className)
        writeFile(filePath: baseJavaPath, content: beanCode)
    }

    /**
     * 生成格式化的代码
     * @param package 包名映射java代码第一行
     * @param jz 属性
     * @param className 类名
     *
     * @return 格式化后的代码内容
     */
    func javaBeanCode(package: String, jz: Dictionary<String, NSObject>, className: String) -> String {
        //TODO 此处差一个数据类型转换的过程！！！
        var javaCode = "package \(package);"
        javaCode += "\n"
        javaCode += "import com.jfinal.plugin.activerecord.Model;"
        javaCode += "\n"
        javaCode += "import com.jfinal.plugin.activerecord.IBean;"
        javaCode += "\n"
        javaCode += "/**"
        javaCode += " * Generated by http://blog.easymbol.com, do not modify this file."
        javaCode += " */"
        javaCode += "@SuppressWarnings(\"serial\")"
        javaCode += "public abstract class Base\(className)<M extends Base\(className)<M>> extends Model<M> implements IBean {"
        javaCode += "\n"
        for item in jz {
            javaCode += "\tpublic void set\(item.key)(\(item.value) \(item.key) {"
            javaCode += "\n"
            javaCode += "\t\tset(\"\(item.key)\", \(item.key));"
            javaCode += "\n"
            javaCode += "\t}"
            javaCode += "\n"
            javaCode += "\tpublic \(item.value) get\(item.key)() {"
            javaCode += "\n"
            javaCode += "\t\treturn get\(item.key)(\"\(item.key)\");"
            javaCode += "\n"
            javaCode += "\t}"
        }
        javaCode += "}"
        return javaCode
    }

    /**
     * 连接数据库
     * @param dbtype 数据库类型[String]
     * @param sqladd 数据库链接地址[String]
     * @param dbname 数据库名[String]
     * @param dbuser 数据库用户名[String]
     * @param dbpwd  数据库登陆密码[String]
     * @param dbport 端口号[int]
     */
    func connectDB(dbtype: String, sqladd: String, dbname: String, dbuser: String, dbpwd: String, dbport: Int) {

    }

    /**
     *  写文件到本地
     * @param filePath 路径,包括文件名和文件类型 eg:/user/xxx/Desktop/1.txt
     * @param content 内容
     */
    func writeFile(filePath: String, content: String) {
        do {
            try content.write(toFile: filePath, atomically: true, encoding: String.Encoding.utf8)
        } catch let error as NSError {
            print("Failed writing to: \(filePath), Error: " + error.localizedDescription)
        }
    }

    /**
     *  读取本地文件
     *  @param filename 文件名
     *  @param filetype 文件类型
     */
    func loadFile(filename: String, filetype: String) -> String? {
        let path = Bundle.main.url(forResource: filename, withExtension: filetype)
        let data = try! Data(contentsOf: path!)
        let string = String(data: data, encoding: String.Encoding.utf8)
        return string
    }

    /**
     * 获取网络文件
     * @param strurl 下载地址
     * @param path  存储路径,以/结尾
     * @param fileName 文件名[包含格式]
     */
    func getFile(strurl: String, path: String, fileName: String) {
        //下载地址
        let url = URL(string: strurl)
        //请求
        let request = URLRequest(url: url!)
        let session = URLSession.shared
        //下载任务
        let downloadTask = session.downloadTask(with: request, completionHandler: { (location: URL?, response: URLResponse?, error: Error?) -> Void in
            //输出下载文件原来的存放目录
//            print("location:\(String(describing: location))")
            //location位置转换
            let locationPath = location!.path
            //拷贝到用户目录
            let documnets: String = path + fileName
            //创建文件管理器
            let fileManager = FileManager.default
            try! fileManager.moveItem(atPath: locationPath, toPath: documnets)
//            print("new location:\(documnets)")
        })

        //使用resume方法启动任务
        downloadTask.resume()
    }

    /**
     * 获取HTML源码
     * @param strurl 获取源码路径
     */
    func getHTMLCode(strurl: String) -> String! {
        let pagecode = try? NSString(contentsOf: URL(string: strurl)!, encoding: String.Encoding.utf8.rawValue)
        return pagecode as String?
    }

}
